-- leader key 为空
vim.g.mapleader = ";"
vim.g.maplocalleader = ";"

local opt = {
    noremap = true,
    silent = true
}

-- 本地变量
local map = vim.api.nvim_set_keymap

-- 剪切板
-- map("v", "<leader>c", '"+y', opt)
-- map("n", "<leader>v", '"+p', opt)
-- map("i", "<leader>v", '<esc>"+p', opt)

-- $跳到行尾不带空格 (交换$ 和 g_)
--map("v", "g_", "$", opt)
--map("n", "$", "g_", opt)
--map("n", "g_", "$", opt)

-- 命令行下 Ctrl+j/k  上一个下一个
map("c", "<C-j>", "<C-n>", { noremap = false })
map("c", "<C-k>", "<C-p>", { noremap = false })

-- save file
-- map("n", "<C-s>", ":w<CR>", opt)
-- map("n", "<leader>q", ":q<CR>", opt)
-- map("n", "<leader>q!", ":quitall!<CR>", opt)
-- map("n", "qq", ":q!<CR>", opt)
-- map("n", "<leader>w", ":w<CR>", opt)
--map("n", "<leader>q", ":qa!<CR>", opt)
-- map("n", "<leader>qa", ":quitall<CR>", opt)

-- fix :set wrap
vim.keymap.set("n", "j", "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true })
vim.keymap.set("n", "k", "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })

-- 上下滚动浏览
-- map("n", "<C-j>", "5j", opt)
-- map("n", "<C-k>", "5k", opt)
-- map("v", "<C-j>", "5j", opt)
-- map("v", "<C-k>", "5k", opt)
-- ctrl u / ctrl + d  只移动9行，默认移动半屏
-- map("n", "<C-u>", "10k", opt)
-- map("n", "<C-d>", "10j", opt)

-- magic search
-- map("n", "/", "/\\v", { noremap = true, silent = false })
-- map("v", "/", "/\\v", { noremap = true, silent = false })
--
-- visual模式下缩进代码
-- map("v", "<", "<gv", opt)
-- map("v", ">", ">gv", opt)
-- 上下移动选中文本
map("v", "J", ":move '>+1<CR>gv-gv", opt)
map("v", "K", ":move '<-2<CR>gv-gv", opt)

-- 在visual mode 里粘贴不要复制
-- map("v", "p", '"_dP', opt)

-- insert 模式下，跳到行首行尾
-- map("i", "<C-h>", "<ESC>I", opt)
-- map("i", "<C-l>", "<ESC>A", opt)


------------------------------------------------------------------
-- windows 分屏快捷键
------------------------------------------------------------------
-- 取消 s 默认功能
--map("n", "s", "", opt)
--map("n", "sv", ":vsp<CR>", opt)
--map("n", "sh", ":sp<CR>", opt)
--map("n", "sc", "<C-w>c", opt) -- 关闭当前
--map("n", "so", "<C-w>o", opt) -- 关闭其他

-- alt + hjkl  窗口之间跳转
-- map("n", "<A-h>", "<C-w>h", opt)
-- map("n", "<A-j>", "<C-w>j", opt)
-- map("n", "<A-k>", "<C-w>k", opt)
-- map("n", "<A-l>", "<C-w>l", opt)
--
-- <leader> + hjkl 窗口之间跳转
-- map("n", "<leader>h", "<C-w>h", opt)
-- map("n", "<leader>j", "<C-w>j", opt)
-- map("n", "<leader>k", "<C-w>k", opt)
-- map("n", "<leader>l", "<C-w>l", opt)

-- 上下左右缩放
-- map("n", "<C-S-Up>", ":resize -2<CR>", opt)
-- map("n", "<C-S-Down>", ":resize +2<CR>", opt)
-- map("n", "<C-S-Left>", ":vertical resize +2<CR>", opt)
-- map("n", "<C-S-Right>", ":vertical resize -2<CR>", opt)
-- 相等比例
--map("n", "s=", "<C-w>=", opt)

-- Terminal相关
-- map("n", "st", ":sp | terminal<CR>", opt)
-- map("n", "stv", ":vsp | terminal<CR>", opt)

-- Esc 回 Normal 模式
map("t", "<Esc>", "<C-\\><C-n>", opt)
map("t", "<A-h>", [[ <C-\><C-N><C-w>h ]], opt)
map("t", "<A-j>", [[ <C-\><C-N><C-w>j ]], opt)
map("t", "<A-k>", [[ <C-\><C-N><C-w>k ]], opt)
map("t", "<A-l>", [[ <C-\><C-N><C-w>l ]], opt)
-- map("t", "<leader>h", [[ <C-\><C-N><C-w>h ]], opt)
-- map("t", "<leader>j", [[ <C-\><C-N><C-w>j ]], opt)
-- map("t", "<leader>k", [[ <C-\><C-N><C-w>k ]], opt)
-- map("t", "<leader>l", [[ <C-\><C-N><C-w>l ]], opt)


--------------------------------------------------------------------
-- 插件快捷键
local keybinding = {}

-----------------------------------------------------------------------------
-- < 常用快捷键 >
-----------------------------------------------------------------------------

--map("n", "<leader>1", ":NvimTreeToggle <CR>", opt)
--map("n", "<leader>2", ":NvimTreeFocus <CR>", opt)
map("n", "<leader>1", ":NeoTreeShowToggle<CR>", opt)
-- map("n", "<leader>tt", ":NERDTreeToggle<CR>", opt)
map("n", "<leader>2", ":NeoTreeReveal<CR>", opt)
map("n", "<leader>3", "<cmd>SymbolsOutline<CR>", opt)
-- map("n", "<leader>4", "<cmd>lua vim.diagnostic.setloclist()<CR>", opt)
-- map("n", "<leader>44", "<cmd>TroubleToggle loclist<CR>", opt)
 map("n", "<leader>4", "<cmd>TroubleToggle document_diagnostics<CR>", opt)
-- map("n", "<leader>5", "<cmd>lua vim.diagnostic.setqflist()<CR>", opt)
-- map("n", "<leader>55", "<cmd>TroubleToggle quickfix<CR>", opt)
map("n", "<leader>5", "<cmd>TroubleToggle workspace_diagnostics<CR>", opt)
map("n", "<leader>6", "<cmd>TodoTrouble<CR>", opt)
map("n", "<leader>0", "<cmd>lua require('dapui').toggle()<CR>", opt)
-- map("n", "<leader><leader>1", "<cmd>lua require('plugin.toggleterm').toggleA()<CR>", opt)
-- map("n", "<leader><leader>2", "<cmd>lua require('plugin.toggleterm').toggleB()<CR>", opt)
-- map("n", "<leader><leader>3", "<cmd>lua require('plugin.toggleterm').toggleC()<CR>", opt)
-- map("n", "<leader><leader>4", "<cmd>lua require('plugin.toggleterm').toggleG()<CR>", opt)
-- map("n", "<leader><leader>`", "<cmd>lua require('plugin.toggleterm').toggle()<CR>", opt)
-- map("n", "<leader>tt", ":NvimTreeToggle <CR>", opt)
-- map("n", "<leader>tb", "<cmd>Vista!!<CR>", opt)
-- 跳转到定义
map("n", "gd", "<cmd>lua vim.lsp.buf.definition()<CR>", opt)

map("n", "<leader>g", "<cmd>TroubleToggle lsp_definitions<CR>", opt)
map("n", "<leader>gg", "<cmd>lua require('goto-preview').goto_preview_definition()<CR>", opt)
map("n", "<leader>ggg", "<cmd>Lspsaga preview_definition<CR>", opt)
map("n", "<leader>f", "<cmd>TroubleToggle lsp_references<CR>", opt)
map("n", "<leader>ff", "<cmd>lua require('goto-preview').goto_preview_references()<CR>", opt)
map("n", "<leader>fff", "<cmd>Lspsaga lsp_finder<CR>", opt)
-- map("n", "<leader>gg", "<cmd>lua vim.lsp.buf.definition()<CR>", opt)
-- 重命名
map("n", "<leader>r", "<cmd>Lspsaga rename<CR>", opt)
map("n", "<leader>?", "<cmd>Lspsaga hover_doc<CR>", opt)
map("n", "<leader>m", "<cmd>lua vim.lsp.buf.code_action()<CR>", opt)
map("n", "<leader>=", ":Format<CR>", opt)
map("v", "<leader>=", ":Format<CR>", opt)
map("n", "<C-p>", ":Telescope find_files<CR>", opt)
map("n", "<leader>sf", "<cmd>lua require('spectre').open_file_search()<CR>", opt)
map("n", "<leader>sp", "<cmd>lua require('spectre').open()<CR>", opt)
map("n", "<leader>sw", "<cmd>lua require('spectre').open_visual({select_word=true})<CR>", opt)
map("n", "<leader>n", "<cmd>Lspsaga diagnostic_jump_next<cr>", opt)
map("n", "<leader><S-n>", "<cmd>Lspsaga diagnostic_jump_prev<cr>", opt)


-----------------------------------------------------------------------------
-- < Lspsaga >
-----------------------------------------------------------------------------
map("n", "<space>lr", "<cmd>Lspsaga rename<CR>", opt)
map("n", "<space>lx", "<cmd>Lspsaga code_action<CR>", opt)
map("n", "<space>lf", "<cmd>Lspsaga lsp_finder<CR>", opt)
map("n", "<space>le", "<cmd>Lspsaga show_line_diagnostics<CR>", opt)
map("n", "<space>lj", "<cmd>Lspsaga diagnostic_jump_next<cr>", opt)
map("n", "<space>lk", "<cmd>Lspsaga diagnostic_jump_prev<cr>", opt)


-----------------------------------------------------------------------------
-- < LSP >
-----------------------------------------------------------------------------
map("n", "<space>cr", "<cmd>lua vim.lsp.buf.rename()<CR>", opt)
map("n", "<space>cx", "<cmd>lua vim.lsp.buf.code_action()<CR>", opt)
map("n", "<space>cd", "<cmd>lua vim.lsp.buf.definition()<CR>", opt)
map("n", "<space>cD", "<cmd>lua vim.lsp.buf.declaration()<CR>", opt)
map("n", "<space>cm", "<cmd>lua vim.lsp.buf.implementation()<CR>", opt)
map("n", "<space>cH", "<cmd>lua vim.lsp.buf.signature_help()<CR>", opt)
map("n", "<space>ch", "<cmd>lua vim.lsp.buf.hover()<CR>", opt)
map("n", "<space>c=", "<cmd>lua vim.lsp.buf.format({sync=true})<CR>", opt)
map("n", "<space>cwa", "<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>", opt)
map("n", "<space>cwr", "<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>", opt)
map("n", "<space>cwl", "<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>", opt)
map("n", "<space>cf", "<cmd>lua vim.lsp.buf.references()<CR>", opt)
map("n", "<space>ci", ":LspInfo<CR>", opt)
map("n", "<space>c4", "<cmd>lua vim.diagnostic.setloclist()<CR>", opt)
map("n", "<space>c5", "<cmd>lua vim.diagnostic.setqflist()<CR>", opt)
map("n", "<space>ce", "<cmd>lua vim.diagnostic.open_float()<CR>", opt)
map("n", "<space>cj", "<cmd>lua vim.diagnostic.goto_next()<CR>", opt)
map("n", "<space>ck", "<cmd>lua vim.diagnostic.goto_prev()<CR>", opt)


-----------------------------------------------------------------------------
-- < trouble >
-----------------------------------------------------------------------------
map("n", "<space>xx", "<cmd>TroubleToggle <CR>", opt)
map("n", "<space>xw", "<cmd>TroubleToggle workspace_diagnostics<CR>", opt)
map("n", "<space>xd", "<cmd>TroubleToggle document_diagnostics<CR>", opt)
map("n", "<space>xq", "<cmd>TroubleToggle quickfix<CR>", opt)
map("n", "<space>xl", "<cmd>TroubleToggle loclist<CR>", opt)
map("n", "<space>xf", "<cmd>TroubleToggle lsp_references<CR>", opt)
map("n", "<space>xt", "<cmd>TroubleToggle lsp_tlsp_type_definitionsype_definitions<CR>", opt)
map("n", "<space>xg", "<cmd>TroubleToggle lsp_definitions<CR>", opt)
map("n", "<space>xp", "<cmd>TroubleToggle telescope<CR>", opt)


-----------------------------------------------------------------------------
-- < go to preview >
-----------------------------------------------------------------------------
--- go to preview 装逼插件
-- definition = "md",
--         implementation = "mi",
--         all_win = "mc",
--         references = "mr",
--         -- /<leader>gd
--         gotoGile = "gd"

keybinding["goto-preview"] = function()
    return {
        {"<space>pd", "<cmd>lua require('goto-preview').goto_preview_definition()<CR>", "n", opt},
        {"<space>pt", "<cmd>lua require('goto-preview').goto_preview_type_definition()<CR>", "n", opt},
        {"<space>pi", "<cmd>lua require('goto-preview').goto_preview_implementation()<CR>", "n", opt},
        {"<space>pq", "<cmd>lua require('goto-preview').close_all_win()<CR>", "n", opt},
        {"<space>pf", "<cmd>lua require('goto-preview').goto_preview_references()<CR>", "n", opt},
    }
end



-----------------------------------------------------------------------------
-- < symbols-outline >
-----------------------------------------------------------------------------
-- map("n", "<leader>3", "SymbolsOUtline<CR>", opt)


-----------------------------------------------------------------------------
-- < treesitter >
-----------------------------------------------------------------------------
-- map("n", "zz", ":foldclose<CR>", opt)
-- map("n", "Z", ":foldopen<CR>", opt)
-- 格式化插件
--map("n", "<leader>=", "<cmd>Neoformat<CR>", opt)


-----------------------------------------------------------------------------
-- < hop >
-----------------------------------------------------------------------------
keybinding["hop"] = function()
    return {
        {"<space>ew", "<cmd>HopWord<CR>", "n", opt},
        {"<space>el", "<cmd>HopLine<CR>", "n", opt},
        {"<space>ec", "<cmd>HopChar1<CR>", "n", opt},
    }
end

-----------------------------------------------------------------------------
-- < spectre >
-----------------------------------------------------------------------------
keybinding["spectre"] = function()
    -- map("n", "<cr>","<cmd>lua require('spectre.actions').select_entry()<CR>", opt )
    return {

        {"<space>sp", "<cmd>lua require('spectre').open()<cr>", "n", opt},
        {"<space>sf", "<cmd>lua require('spectre').open_file_search()<cr>", "n", opt},
        {"<space>sw", "<cmd>lua require('spectre').open_visual({select_word=true})<cr>", "n", opt},
    }
end


-- < nvim-tree >
-----------------------------------------------------------------------------
-- map("n", ",tt", ":NvimTreeToggle <CR>", opt)
-- map("n", ",tr", ":NvimTreeRefresh <CR>", opt)
-- map("n", ",tf", ":NvimTreeFindFile <CR>", opt)

-- 列表快捷键
keybinding["nvim-tree"] = {
    -- 打开文件或文件夹
    { key = { "<CR>", "o", "<2-LeftMouse>" }, action = "edit" },
    -- v分屏打开文件
    { key = "v", action = "vsplit" },
    -- h分屏打开文件
    { key = "h", action = "split" },
    -- Ignore (node_modules)
    { key = "i", action = "toggle_ignored" },
    -- Hide (dotfiles)
    { key = ".", action = "toggle_dotfiles" },
    { key = "R", action = "refresh" },
    -- 文件操作
    { key = "a", action = "create" },
    { key = "d", action = "remove" },
    { key = "r", action = "rename" },
    { key = "x", action = "cut" },
    { key = "c", action = "copy" },
    { key = "p", action = "paste" },
    { key = "y", action = "copy_name" },
    { key = "Y", action = "copy_path" },
    { key = "gy", action = "copy_absolute_path" },
    { key = "I", action = "toggle_file_info" },
    { key = "n", action = "tabnew" },
    -- 进入下一级
    { key = { "]" }, action = "cd" },
    -- 进入上一级
    { key = { "[" }, action = "dir_up" },
    { key = "s", action = "system_open" }
}




-----------------------------------------------------------------------------
-- < bufferline >
-----------------------------------------------------------------------------

keybinding["bufferline"] = function()
    return {
        -- 左右Tab切换
        {"<TAB>", ":BufferLineCycleNext<CR>", "n", opt},
        {"<S-Tab>", ":BufferLineCyclePrev<CR>", "n", opt},
        -- "moll/vim-bbye" 关闭当前 buffer
        {"<space>bc", ":Bdelete!<CR>", "n", opt},
        -- 关闭左/右侧标签页
        {"<space>bh", ":BufferLineCloseLeft<CR>", "n", opt},
        {"<space>bl", ":BufferLineCloseRight<CR>", "n", opt},
        -- 关闭其他标签页
        {"<space>bo", ":BufferLineCloseRight<CR>:BufferLineCloseLeft<CR>", "n", opt},
        -- 关闭选中标签页
        {"<space>bp", ":BufferLinePickClose<CR>", "n", opt},
    }
end


-----------------------------------------------------------------------------
-- < Telescope >
-----------------------------------------------------------------------------
keybinding["telescope"] = function()
    return {
        --map{"<C-p>", ":Telescope find_files<CR>", "n", opt},
        --map{"<C-f>", ":Telescope live_grep<CR>", "n", opt},
        {"<space>fm", ":Telescope marks <CR>", "n", opt},
        {"<space>fb", ":Telescope buffers <CR>", "n", opt},
        {"<space>ff", ":Telescope find_files <CR>", "n", opt},
        {"<space>fg", ":Telescope live_grep <CR>", "n", opt},
        {"<space>fa", ":Telescope find_files follow=true no_ignore=true hidden=true <CR>", "n", opt},
        {"<space>fh", ":Telescope help_tags <CR>", "n", opt},
        {"<space>fo", ":Telescope oldfiles <CR>", "n", opt},
        {"<space>fp", ":Telescope projects<CR>", "n", opt},
        {"<space>fc", ":Telescope git_commits <CR>", "n", opt},
        {"<space>fs", ":Telescope git_status <CR>", "n", opt},
        {"<space>fe", ":Telescope env<CR>", "n", opt},
        {"<space>ft", "<cmd>TodoTelescope<cr>", "n", opt},
    }
end

-- Telescope 列表中 插入模式快捷键
keybinding.telescope_mappings = {
    i = {
        -- 上下移动
        ["<C-j>"] = "move_selection_next",
        ["<C-k>"] = "move_selection_previous",
        ["<C-n>"] = "move_selection_next",
        ["<C-p>"] = "move_selection_previous",
        -- 历史记录
        ["<Down>"] = "cycle_history_next",
        ["<Up>"] = "cycle_history_prev",
        -- 关闭窗口
        -- ["<esc>"] = actions.close,
        ["<C-c>"] = "close",
        -- 预览窗口上下滚动
        ["<C-b>"] = "preview_scrolling_up",
        ["<C-f>"] = "preview_scrolling_down",
    },
}

-----------------------------------------------------------------------------
-- < vista >
-----------------------------------------------------------------------------
-- map("n", "<leader>3", "<cmd>Vista!!<CR>", opt)


-----------------------------------------------------------------------------
-- < comment >
-----------------------------------------------------------------------------
-- 代码注释插件
-- see ./lua/plugin-config/comment.lua
keybinding.comment = {
    -- Normal 模式快捷键
    toggler = {
        -- line = "<leader>/",
        -- block = "<leader>//"
        line = "gcc",
        block = "gbc"
    },
    -- Visual 模式
    opleader = {
        line = "gc",
        block = "gb"
    }
}
--map("n", "<leader>/", ",t", { noremap = false })
--map("n", "<leader>//", ",tt", { noremap = false })
--map("v", "<leader>/", ",l", { noremap = false })
--map("v", "<leader>//", ",ll", { noremap = false })


-----------------------------------------------------------------------------
-- < switch >
-----------------------------------------------------------------------------
-- map("n", "g]", ":Switch<cr>", opt)
-- vim_dadbod_ui
-- map("n", "<leader>4", ":DBUIToggle<cr>")


-----------------------------------------------------------------------------
-- < todo-comments >
-----------------------------------------------------------------------------

keybinding["todo-comments"] = function()
    return {
        -- {, "<cmd>TodoTelescope theme=dropdown<cr>")
        -- {"<space>todo", "<cmd>TodoTelescope theme=dropdown<cr>", "n", opt},
        {"<space>todo", "<cmd>TodoTelescope<cr>", "n", opt},
    }
end

-----------------------------------------------------------------------------
-- < ToggleTerm >
-----------------------------------------------------------------------------
keybinding["toggleterm"] = function()
    local context = nil
    local create_terminal_context = function()
        if context ~= nil then
            return context
        end
        local Terminal = require("toggleterm.terminal").Terminal
        local lazygit = Terminal:new({
            cmd = "lazygit",
            dir = "git_dir",
            direction = "float",
            float_opts = {
                border = "double",
            },
            on_open = function(term)
                vim.cmd("startinsert!")
                -- q / <leader>tg 关闭 terminal
                vim.api.nvim_buf_set_keymap(term.bufnr, "n", "q", "<cmd>close<CR>", { noremap = true, silent = true })
                vim.api.nvim_buf_set_keymap(term.bufnr, "n", "<leader>tg", "<cmd>close<CR>", { noremap = true, silent = true })
                -- ESC 键取消，留给lazygit
                if vim.fn.mapcheck("<Esc>", "t") ~= "" then
                    vim.api.nvim_del_keymap("t", "<Esc>")
                end
            end,
            on_close = function(_)
                -- 添加回来
                vim.api.nvim_set_keymap("t", "<Esc>", "<C-\\><C-n>", {
                    noremap = true,
                    silent = true,
                })
            end,
        })
        context = {
            ta = Terminal:new({
                direction = "tab",
                -- direction = "horizontal",
                close_on_exit = true,
            }),
            tb = Terminal:new({
                --direction = "vertical",
                direction = "tab",
                -- direction = "horizontal",
                close_on_exit = true,
            }),
            tc = Terminal:new({
                -- direction = "float",
                direction = "tab",
                --direction = "horizontal",
                -- direction = "horizontal",
                close_on_exit = true,
            }),
            lazygit = lazygit,
        }
        return context
    end

    local toggleA = function()
        local ctx = create_terminal_context()
        if ctx.current == nil then
            ctx.ta:open()
            ctx.current = ctx.ta
        elseif ctx.current == ctx.ta then
            if ctx.ta:is_open() then
                ctx.ta:close()
            else
                ctx.ta:open()
            end
        else
            ctx.current:close()
            ctx.ta:open()
            ctx.current = ctx.ta
        end
    end

    local toggleB = function()
        local ctx = create_terminal_context()
        if ctx.current == nil then
            ctx.tb:open()
            ctx.current = ctx.tb
        elseif ctx.current == ctx.tb then
            if ctx.tb:is_open() then
                ctx.tb:close()
            else
                ctx.tb:open()
            end
        else
            ctx.current:close()
            ctx.tb:open()
            ctx.current = ctx.tb
        end
    end

    local toggleC = function()
        local ctx = create_terminal_context()
        if ctx.current == nil then
            ctx.tc:open()
            ctx.current = ctx.tc
        elseif ctx.current == ctx.tc then
            if ctx.tc:is_open() then
                ctx.tc:close()
            else
                ctx.tc:open()
            end
        else
            ctx.current:close()
            ctx.tc:open()
            ctx.current = ctx.tc
        end
    end

    local toggleG = function()
        local ctx = create_terminal_context()
        ctx.lazygit:toggle()
    end

    local toggle = function()
        local ctx = create_terminal_context()
        if ctx.current == nil then
            toggleA()
        else
            if ctx.current:is_open() then
                ctx.current:close()
            else
                ctx.current:open()
            end
        end
    end
    vim.keymap.set({ "n", "t" }, "<space>m1", toggleA)
    vim.keymap.set({ "n", "t" }, "<space>m2", toggleB)
    vim.keymap.set({ "n", "t" }, "<space>m3", toggleC)
    vim.keymap.set({ "n", "t" }, "<space>mg", toggleG)
    -- vim.keymap.set({ "n", "t" }, ",m", toggleA)
    return {
        -- {"<Esc>", "<C-\\><C-n>", "t", opt},
        {"<leader><leader>`", toggle, {"n", "t"}, opt},
        {"<leader><leader>1", toggleA, {"n", "t"}, opt},
        {"<leader><leader>2", toggleB, {"n", "t"}, opt},
        {"<leader><leader>3", toggleC, {"n", "t"}, opt},
        {"<leader><leader>4", toggleG, {"n", "t"}, opt},
    }
    -- 打开普通终端
    --map("n", ",tb", "<cmd>exe v:count.'ToggleTerm'<CR>", opt)
    -- 打开浮动终端
    --map("n", ",tf", "<cmd>lua require('toggleterm').float_toggle()<CR>", opt)
    -- 打开lazy git 终端
    --map("n", ",tg", "<cmd>lua require('toggleterm').lazygit_toggle()<CR>", opt)
    -- 打开或关闭所有终端
    -- map("n", ",ta", "<cmd>ToggleTermToggleAll<CR>", opt)
end

-----------------------------------------------------------------------------
-- < lsp/ts.lua>
-----------------------------------------------------------------------------
-- typescript 快捷键
keybinding.mapTsLSP = function(mapbuf)
    mapbuf("n", "gs", ":TSLspOrganize<CR>", opt)
    mapbuf("n", "gR", ":TSLspRenameFile<CR>", opt)
    mapbuf("n", "gi", ":TSLspImportAll<CR>", opt)
end

-----------------------------------------------------------------------------
-- < dap >
-----------------------------------------------------------------------------

keybinding["nvim-dap-ui"] = function()
    return {
        {"<space>dg", ":lua require'dap'.continue()<CR>", "n", opt},
        {"<space>dc", ":lua require'dap'.continue()<CR>", "n", opt},
        {"<space>dt", ":lua require'dap'.toggle_breakpoint()<CR>", "n", opt},
        {"<space>dj", ":lua require'dap'.step_over()<CR>", "n", opt},
        {"<space>dk", ":lua require'dap'.step_out()<CR>", "n", opt},
        {"<space>dl", ":lua require'dap'.step_into()<CR>", "n", opt},
    }
end


-----------------------------------------------------------------------------
-- < vimspector >
-----------------------------------------------------------------------------
keybinding.vimspector = function()
    -- 开始
    map("n", "<space>dg", ":call vimspector#Launch()<CR>", opt)
    -- 结束
    map("n", "<space>de", ":call vimspector#Reset()<CR>", opt)
    -- 继续
    map("n", "<space>dc", ":call vimspector#Continue()<CR>", opt)
    -- 设置断点
    map("n", "<space>dt", ":call vimspector#ToggleBreakpoint()<CR>", opt)
    map("n", "<space>dd", ":call vimspector#ClearBreakpoints()<CR>", opt)
    --  stepOver, stepOut, stepInto
    map("n", "<space>dj", "<Plug>VimspectorStepOver", opt)
    map("n", "<space>dk", "<Plug>VimspectorStepOut", opt)
    map("n", "<space>dl", "<Plug>VimspectorStepInto", opt)
end

-----------------------------------------------------------------------------
-- < nvim-cmp >
-----------------------------------------------------------------------------
keybinding.cmp = function(cmp)
    local feedkey = function(key, mode)
        vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(key, true, true, true), mode, true)
    end
    local has_words_before = function()
        local line, col = unpack(vim.api.nvim_win_get_cursor(0))
        return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
    end
    local luasnip = require 'luasnip'

    return {
        -- 上一个
        ["<C-k>"] = cmp.mapping.select_prev_item(),
        -- 下一个
        ["<C-j>"] = cmp.mapping.select_next_item(),
        -- 出现补全
        ["<A-.>"] = cmp.mapping(cmp.mapping.complete(), { "i", "c" }),
        -- 取消
        ["<Esc>"] = cmp.mapping(
            {
                i = cmp.mapping.abort(),
                c = cmp.mapping.close()
            }
        ),
        -- 确认
        -- Accept currently selected item. If none selected, `select` first item.
        -- Set `select` to `false` to only confirm explicitly selected items.
        ["<CR>"] = cmp.mapping.confirm(
            {
                select = true,
                behavior = cmp.ConfirmBehavior.Replace
            }
        ),
        -- ['<C-y>'] = cmp.config.disable, -- Specify `cmp.config.disable` if you want to remove the default `<C-y>` mapping.
        -- 如果窗口内容太多，可以滚动
        ["<C-u>"] = cmp.mapping(cmp.mapping.scroll_docs(-4), { "i", "c" }),
        ["<C-d>"] = cmp.mapping(cmp.mapping.scroll_docs(4), { "i", "c" }),


        -- snippets 跳转
        ["<C-l>"] = cmp.mapping(
            function(_)
                if luasnip.expand_or_jumpable() then
                    luasnip.expand_or_jump()
                end
                -- if vim.fn["vsnip#available"](1) == 1 then
                    -- feedkey("<Plug>(vsnip-expand-or-jump)", "")
                -- end
            end,
            { "i", "s" }
        ),
        ["<C-h>"] = cmp.mapping(
            function()
                if luasnip.jumpable(-1) then
                    luasnip.jump(-1)
                end
                -- if vim.fn["vsnip#jumpable"](-1) == 1 then
                    -- feedkey("<Plug>(vsnip-jump-prev)", "")
                -- end
            end,
            { "i", "s" }
        ),
        -- super Tab
        ["<Tab>"] = cmp.mapping(
            function(fallback)
                if cmp.visible() then
                    cmp.select_next_item()
                elseif luasnip.expand_or_jumpable() then
                    luasnip.expand_or_jump()
                -- elseif vim.fn["vsnip#available"](1) == 1 then
                    -- feedkey("<Plug>(vsnip-expand-or-jump)", "")
                elseif has_words_before() then
                    cmp.complete()
                else
                    fallback() -- The fallback function sends a already mapped key. In this case, it's probably `<Tab>`.
                end
            end,
            { "i", "s" }
        ),
        ["<S-Tab>"] = cmp.mapping(
            function()
                if cmp.visible() then
                    cmp.select_prev_item()
                elseif luasnip.jumpable(-1) then
                    luasnip.jump(-1)
                -- elseif vim.fn["vsnip#jumpable"](-1) == 1 then
                    -- feedkey("<Plug>(vsnip-jump-prev)", "")
                end
            end,
            { "i", "s" }
        )
        -- end of super Tab
    }
end

-----------------------------------------------------------------------------
-- < gitsigns >
-----------------------------------------------------------------------------
keybinding.gitsigns_on_attach = function(bufnr)
    local gs = package.loaded.gitsigns
    local function map(mode, l, r, opts)
        opts = opts or {}
        opts.buffer = bufnr
        vim.keymap.set(mode, l, r, opts)
    end

    -- Navigation
    map("n", "<space>gj",
        function()
            if vim.wo.diff then return "]c" end
            vim.schedule(function() gs.next_hunk() end) return "<Ignore>"
        end,
        { expr = true }
    )
    map("n", "<space>gk",
        function()
            if vim.wo.diff then return "[c" end
            vim.schedule(function() gs.prev_hunk() end) return "<Ignore>"
        end,
        { expr = true }
    )
    map({ "n", "v" }, "<space>gs", ":Gitsigns stage_hunk<CR>")
    map({ "n", "v" }, "<space>gr", ":Gitsigns reset_hunk<CR>")

    map("n", "<space>gS", gs.stage_buffer)
    map("n", "<space>gR", gs.reset_buffer)    -- 取消本地的修改
    map("n", "<space>gu", gs.undo_stage_hunk) -- 取消暂存区的修改
    map("n", "<space>gp", gs.preview_hunk)
    map("n","<space>gb", function() gs.blame_line({ full = true }) end)
    map("n", "<space>gd", gs.diffthis)
    map("n", "<space>gD", function() gs.diffthis("~") end)
    -- toggle
    map("n", "<space>gtd", gs.toggle_deleted)
    map("n", "<space>gtb", gs.toggle_current_line_blame)
    -- Text object
    map({ "o", "x" }, "ig", ":<C-U>Gitsigns select_hunk<CR>")
end

return keybinding
